#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_all.hpp>
#include <asio.hpp>
#include "async_mysql.hpp"

using namespace async_mysql;
using namespace std::chrono_literals;

// 测试数据库配置（需要根据实际环境修改）
const connection_config test_config {
    .host = "localhost",
    .user = "test_user",
    .password = "test_password",
    .database = "test_db",
    .port = 3306,
    .timeout_sec = 5
};

// 测试表结构
const std::string create_table_sql = R"(
CREATE TABLE IF NOT EXISTS test_users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
)";

const std::string drop_table_sql = "DROP TABLE IF EXISTS test_users";

// 测试数据
const std::string insert_data_sql = R"(
INSERT INTO test_users (name, email) VALUES 
    ('Alice', 'alice@example.com'),
    ('Bob', 'bob@example.com'),
    ('Charlie', 'charlie@example.com')
)";

// 测试基类，负责数据库初始化和清理
class TestDatabase {
protected:
    void setup() {
        // 创建测试表
        sync_conn conn(test_config);
        conn.connect_throw();
        conn.execute_throw(drop_table_sql);
        conn.execute_throw(create_table_sql);
        conn.execute_throw(insert_data_sql);
    }
    
    void teardown() {
        // 清理测试表
        sync_conn conn(test_config);
        conn.connect_throw();
        conn.execute_throw(drop_table_sql);
    }
};

using sync_conn = connection;
using async_conn = async_connection;

// 测试用例组
TEST_CASE_METHOD(TestDatabase, "Synchronous Connection Tests") {
    setup();
    
    SECTION("Basic connection") {
        sync_conn conn(test_config);
        auto ec = conn.connect();
        REQUIRE_FALSE(ec);
        REQUIRE(conn.is_connected());
    }
    
    SECTION("Failed connection") {
        connection_config bad_config = test_config;
        bad_config.password = "wrong_password";
        
        sync_conn conn(bad_config);
        auto ec = conn.connect();
        REQUIRE(ec);
        REQUIRE(ec == error::connection_failed);
        REQUIRE_FALSE(conn.is_connected());
    }
    
    SECTION("Query execution") {
        sync_conn conn(test_config);
        conn.connect_throw();
        
        auto [ec, rs] = conn.query("SELECT * FROM test_users");
        REQUIRE_FALSE(ec);
        REQUIRE(rs.row_count() == 3);
        
        row r;
        int count = 0;
        while (rs.next(r)) {
            REQUIRE(r.size() == 4);
            count++;
        }
        REQUIRE(count == 3);
    }
    
    SECTION("Data manipulation") {
        sync_conn conn(test_config);
        conn.connect_throw();
        
        // 插入数据
        auto ec = conn.execute("INSERT INTO test_users (name, email) "
                              "VALUES ('David', 'david@example.com')");
        REQUIRE_FALSE(ec);
        REQUIRE(conn.last_insert_id() > 0);
        REQUIRE(conn.affected_rows() == 1);
        
        // 更新数据
        ec = conn.execute("UPDATE test_users SET name = 'Dave' "
                         "WHERE email = 'david@example.com'");
        REQUIRE_FALSE(ec);
        REQUIRE(conn.affected_rows() == 1);
        
        // 删除数据
        ec = conn.execute("DELETE FROM test_users WHERE email = 'david@example.com'");
        REQUIRE_FALSE(ec);
        REQUIRE(conn.affected_rows() == 1);
    }
    
    SECTION("Reconnect after failure") {
        sync_conn conn(test_config);
        conn.connect_throw();
        
        // 模拟连接中断
        conn.close();
        REQUIRE_FALSE(conn.is_connected());
        
        // 重新连接
        auto ec = conn.reconnect();
        REQUIRE_FALSE(ec);
        REQUIRE(conn.is_connected());
        
        // 执行查询验证
        auto [qec, rs] = conn.query("SELECT 1");
        REQUIRE_FALSE(qec);
    }
    
    teardown();
}

TEST_CASE_METHOD(TestDatabase, "Asynchronous Connection Tests") {
    setup();
    
    asio::io_context io;
    
    SECTION("Async connect and query") {
        auto conn = std::make_shared<async_conn>(io, test_config);
        
        bool connect_done = false;
        bool query_done = false;
        
        conn->async_connect([&](std::error_code ec) {
            REQUIRE_FALSE(ec);
            connect_done = true;
            
            conn->async_query("SELECT * FROM test_users", [&](auto ec, auto rs) {
                REQUIRE_FALSE(ec);
                REQUIRE(rs.row_count() == 3);
                query_done = true;
            });
        });
        
        io.run_for(5s);
        REQUIRE(connect_done);
        REQUIRE(query_done);
    }
    
    SECTION("Concurrent async queries") {
        auto conn = std::make_shared<async_conn>(io, test_config);
        conn->connect_throw();
        
        std::atomic<int> completed = 0;
        
        for (int i = 0; i < 5; i++) {
            conn->async_query("SELECT SLEEP(0.1)", [&](auto ec, auto) {
                REQUIRE_FALSE(ec);
                completed++;
            });
        }
        
        io.run_for(1s);
        REQUIRE(completed == 5);
    }
    
    teardown();
}

TEST_CASE_METHOD(TestDatabase, "Synchronous Connection Pool Tests") {
    setup();
    
    SECTION("Basic pool operations") {
        connection_pool pool(test_config, 3);
        
        auto conn = pool.get_connection();
        REQUIRE(conn->is_connected());
        
        auto [ec, rs] = conn->query("SELECT * FROM test_users");
        REQUIRE_FALSE(ec);
        REQUIRE(rs.row_count() == 3);
        
        pool.release_connection(conn);
    }
    
    SECTION("Pool exhaustion and expansion") {
        connection_pool pool(test_config, 2);
        
        auto conn1 = pool.get_connection();
        auto conn2 = pool.get_connection();
        
        // 第三个连接应该等待
        auto start = std::chrono::steady_clock::now();
        std::thread t([&] {
            auto conn3 = pool.get_connection();
            conn3->query("SELECT 1");
            pool.release_connection(conn3);
        });
        
        // 释放一个连接后，等待线程应该获取到连接
        std::this_thread::sleep_for(100ms);
        pool.release_connection(conn1);
        
        t.join();
        auto duration = std::chrono::steady_clock::now() - start;
        REQUIRE(duration < 500ms);
    }
    
    SECTION("Connection proxy automatic release") {
        connection_pool pool(test_config, 2);
        int row_count = 0;
        
        {
            auto proxy = pool.get_connection_proxy();
            auto [ec, rs] = proxy->query("SELECT * FROM test_users");
            REQUIRE_FALSE(ec);
            
            while (rs.next(row{})) {
                row_count++;
            }
        } // 代理在此作用域结束时自动释放连接
        
        // 应该能再次获取连接
        auto proxy2 = pool.get_connection_proxy();
        REQUIRE(proxy2->is_connected());
    }
    
    SECTION("Manual connection release") {
        connection_pool pool(test_config, 2);
        
        auto proxy = pool.get_connection_proxy();
        proxy.disable_auto_release();
        
        REQUIRE(proxy->is_connected());
        proxy.release(); // 手动释放
        
        // 应该能再次获取连接
        auto proxy2 = pool.get_connection_proxy();
        REQUIRE(proxy2->is_connected());
    }
    
    teardown();
}

TEST_CASE_METHOD(TestDatabase, "Asynchronous Connection Pool Tests") {
    setup();
    
    SECTION("Basic async pool") {
        asio::io_context io;
        async_connection_pool pool(io, test_config, 3);
        
        std::atomic<bool> done = false;
        int row_count = 0;
        
        pool.get_connection([&](auto conn) {
            REQUIRE(conn);
            REQUIRE(conn->is_connected());
            
            conn->async_query("SELECT * FROM test_users", [&](auto ec, auto rs) {
                REQUIRE_FALSE(ec);
                row_count = rs.row_count();
                
                pool.release_connection(conn);
                done = true;
            });
        });
        
        io.run_for(5s);
        REQUIRE(done);
        REQUIRE(row_count == 3);
    }
    
    SECTION("Concurrent pool requests") {
        asio::io_context io;
        async_connection_pool pool(io, test_config, 2);
        
        std::atomic<int> completed = 0;
        const int num_requests = 5;
        
        for (int i = 0; i < num_requests; i++) {
            pool.get_connection([&, i](auto conn) {
                REQUIRE(conn);
                
                conn->async_query("SELECT SLEEP(0.1)", [&, conn](auto ec, auto) {
                    REQUIRE_FALSE(ec);
                    pool.release_connection(conn);
                    completed++;
                });
            });
        }
        
        io.run_for(5s);
        REQUIRE(completed == num_requests);
    }
    
    SECTION("Internal IO thread pool") {
        // 使用内部管理的IO上下文
        async_connection_pool pool(2, test_config, 2); // 2个IO线程，2个连接
        
        std::promise<void> done_promise;
        auto done_future = done_promise.get_future();
        
        pool.get_connection([&](auto conn) {
            REQUIRE(conn);
            
            conn->async_query("SELECT * FROM test_users", [&](auto ec, auto rs) {
                REQUIRE_FALSE(ec);
                REQUIRE(rs.row_count() == 3);
                
                pool.release_connection(conn);
                done_promise.set_value();
            });
        });
        
        // 等待异步操作完成
        REQUIRE(done_future.wait_for(5s) == std::future_status::ready);
    }
    
    SECTION("Health check and reconnect") {
        asio::io_context io;
        async_connection_pool pool(io, test_config, 1, 1s); // 1秒健康检查
        
        // 获取连接并故意使其失效
        std::shared_ptr<async_conn> weak_conn;
        pool.get_connection([&](auto conn) {
            weak_conn = conn;
            conn->close(); // 模拟连接断开
            
            // 立即归还连接
            pool.release_connection(conn);
        });
        io.run_for(500ms);
        
        // 再次获取连接（应该自动重新连接）
        std::atomic<bool> valid = false;
        pool.get_connection([&](auto conn) {
            valid = conn->is_connected();
            pool.release_connection(conn);
        });
        
        io.run_for(2s);
        REQUIRE(valid);
    }
    
    teardown();
}

TEST_CASE_METHOD(TestDatabase, "Result Set and Row Tests") {
    setup();
    
    sync_conn conn(test_config);
    conn.connect_throw();
    
    auto [ec, rs] = conn.query("SELECT * FROM test_users ORDER BY id");
    REQUIRE_FALSE(ec);
    
    SECTION("Row access") {
        row r;
        REQUIRE(rs.next(r));
        
        // 通过索引访问
        REQUIRE(r[0] == "1");
        REQUIRE(r[1] == "Alice");
        REQUIRE(r[2] == "alice@example.com");
        
        // 通过列名访问
        REQUIRE(r.at("id") == "1");
        REQUIRE(r.at("name") == "Alice");
        REQUIRE(r.at("email") == "alice@example.com");
        
        // 测试越界访问
        REQUIRE_THROWS_AS(r[4], std::out_of_range);
        REQUIRE_THROWS_AS(r.at("invalid_column"), std::out_of_range);
    }
    
    SECTION("Field names") {
        auto names = rs.field_names();
        REQUIRE(names.size() == 4);
        REQUIRE(names[0] == "id");
        REQUIRE(names[1] == "name");
        REQUIRE(names[2] == "email");
        REQUIRE(names[3] == "created_at");
    }
    
    SECTION("Result set navigation") {
        int count = 0;
        row r;
        while (rs.next(r)) {
            count++;
            REQUIRE(r.at("name") != "");
        }
        REQUIRE(count == 3);
        
        // 尝试在结果集结束后获取数据
        REQUIRE_FALSE(rs.next(r));
    }
    
    SECTION("Move semantics") {
        result_set moved_rs = std::move(rs);
        REQUIRE(moved_rs.row_count() == 3);
        
        // 原始结果集应该无效
        row r;
        REQUIRE_FALSE(rs.next(r));
    }
    
    teardown();
}

TEST_CASE_METHOD(TestDatabase, "Error Handling Tests") {
    setup();
    
    SECTION("Invalid query") {
        sync_conn conn(test_config);
        conn.connect_throw();
        
        auto [ec, rs] = conn.query("SELECT * FROM non_existent_table");
        REQUIRE(ec);
        REQUIRE(ec == error::query_failed);
    }
    
    SECTION("Connection pool exhaustion") {
        connection_pool pool(test_config, 1);
        
        auto conn1 = pool.get_connection();
        auto start = std::chrono::steady_clock::now();
        
        // 尝试获取第二个连接（应该阻塞）
        std::thread t([&] {
            auto conn2 = pool.get_connection(); // 应该阻塞
            pool.release_connection(conn2);
        });
        
        std::this_thread::sleep_for(100ms);
        pool.release_connection(conn1);
        t.join();
        
        auto duration = std::chrono::steady_clock::now() - start;
        REQUIRE(duration < 500ms);
    }
    
    SECTION("Async connection failure") {
        connection_config bad_config = test_config;
        bad_config.password = "wrong_password";
        
        asio::io_context io;
        async_connection_pool pool(io, bad_config, 1);
        
        std::atomic<bool> got_connection = false;
        std::atomic<error> conn_error = error::success;
        
        pool.get_connection([&](auto conn) {
            got_connection = (conn != nullptr);
            if (!conn) {
                conn_error = error::connection_failed;
            }
        });
        
        io.run_for(5s);
        REQUIRE_FALSE(got_connection);
        REQUIRE(conn_error == error::connection_failed);
    }
    
    teardown();
}